#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>  /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <sys/ioctl.h>
#include <stdint.h>
#include <stdlib.h>

#include <readline/readline.h>
#include <readline/history.h>

int      fd;
char     sBuffer[254];
char     sResult[254];

int initport(int fd)
{
    struct termios options;

    // Get the current options for the port...
    tcgetattr(fd, &options);

    // Set the baud rates to whatever is needed... (Max 115200)
    cfsetispeed(&options, B115200);

    // Enable the receiver and set local mode...
    options.c_cflag |= (CLOCAL | CREAD);

    options.c_cflag &= ~PARENB;
    options.c_cflag &= ~CSTOPB;
    options.c_cflag &= ~CSIZE;
    options.c_cflag |= CS8;

    // Set the new options for the port...
    tcsetattr(fd, TCSANOW, &options);

    return 1;
}

int writeport(int fd, char *chars) 
{
    int len = strlen(chars);

    // stick a after the command        (0xd == 13 == ASCII CR)
    chars[len] = 0x0d;

    // terminate the string properly
    chars[len+1] = 0x00;
    int n = write(fd, chars, strlen(chars));
    if (n < 0) {
        fputs("write failed!\n", stderr);
        return 0;
    }

    return 1;                                                                                                           
}

int readport(int fd, char *result) 
{
    int n = read(fd, result, 254);

    //This is needed or the previous contents of the string will appear after the changed characters. 
    result[n-1] = 0x00; 
    if (n <= 0) {
        if (errno == EAGAIN) {
            printf("SERIAL EAGAIN ERROR\n");
            return 0;
        } else {
            printf("SERIAL read error %d %s\n", errno, strerror(errno));
            return 0;
        }
    }

    return 1;
}

int getbaud(int fd) 
{
    struct termios termAttr;
    int inputSpeed = -1;
    speed_t baudRate;
    tcgetattr(fd, &termAttr);
    /* Get the input speed.                              */
    baudRate = cfgetispeed(&termAttr);
    switch (baudRate) 
    {
        case B0:      inputSpeed = 0; break;
        case B50:     inputSpeed = 50; break;
        case B110:    inputSpeed = 110; break;
        case B134:    inputSpeed = 134; break;
        case B150:    inputSpeed = 150; break;
        case B200:    inputSpeed = 200; break;
        case B300:    inputSpeed = 300; break;
        case B600:    inputSpeed = 600; break;
        case B1200:   inputSpeed = 1200; break;
        case B1800:   inputSpeed = 1800; break;
        case B2400:   inputSpeed = 2400; break;
        case B4800:   inputSpeed = 4800; break;
        case B9600:   inputSpeed = 9600; break;
        case B19200:  inputSpeed = 19200; break;
        case B38400:  inputSpeed = 38400; break;
        case B115200: inputSpeed = 115200; break;
    }
    return inputSpeed;
}

int setup()
{
    fd = open("/dev/gsm", O_RDWR | O_NOCTTY | O_NDELAY);
    if (fd == -1) {
        perror("open_port: Unable to open /dev/ttyUSB0 - ");
        return 1;
    } else {
        fcntl(fd, F_SETFL, 0);
        printf("Serial connection established on /dev/ttyUSB0\n");
    }
    initport(fd);

    return 0;
}

int main(int argc, char **argv)
{
    int bytes, i;

    setup();   

    /* don't block serial read */
    //    fcntl(fd, F_SETFL, O_NONBLOCK);


    read_history(NULL);
    while(1) {
        char *line;
        line = readline("GSM900$ ");
        if(strlen(line) == 0) {
            free(line);
            continue;
        }

        add_history(line);
        if(strcmp(line, "esc") == 0) {
            char esc[2] = { 0x1b, 0 };
            writeport(fd, esc);
        } else if(strcmp(line, "z") == 0){
            char z[4];
            z[0] = 0x1A;
            z[1] = 0;
            printf("point 1\n");
            writeport(fd, z);
        } else {
            writeport(fd, line);
        }

        /*
         * Find out how many bytes are sitting in the serial input buffer and only
         * choose to read them when there are enough.  This line populates the
         * bytes integer with the number of bytes sitting in the serial input
         * buffer - FIONREAD not well documented
         */
        /*ioctl(fd, FIONREAD, &bytes); */

        /*
         * tweak this number to gain performance - lower equals faster read but
         * more likely to have erroneous strings
         */
        memset(sBuffer, 0, sizeof(sBuffer));
        if (!readport(fd, sBuffer)) {
            printf("read failed - sBuffer: %s\n", sBuffer);
            //close(fd);
            //return 1;
        }
        int sBuffer_length = strlen(sBuffer);

        /*printf("hex dump %x\n", *((uint32_t*)sBuffer));*/
        for(i = 0; i < sBuffer_length; ++i){
            if(sBuffer[i] != 0x0D && sBuffer[i] != 0x0A){
                printf("%c", sBuffer[i]);
            } 
        }
        printf("\n");

        free(line);
    }

    return 0;
}
